﻿using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using K9Nano.Dependency;
using K9Nano.Domain.Session;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;

namespace K9Nano.AspNetCore.Security;

internal class JwtHelper : IJwtHelper, ISingletonDependency
{
    private readonly JwtOptions _jwtOptions;

    public JwtHelper(IOptions<JwtOptions> JwtOptionsAccessor)
    {
        _jwtOptions = JwtOptionsAccessor.Value;
    }

    public virtual JwtResponse GenerateJwtToken(IEnumerable<Claim> claims)
    {
        // 1. 从 appsettings.json 中读取SecretKey
        var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SecretKey));

        // 2. 选择加密算法
        var algorithm = SecurityAlgorithms.HmacSha256;

        // 3. 生成Credentials
        var signingCredentials = new SigningCredentials(secretKey, algorithm);

        // 4. 根据以上，生成token
        var jwtSecurityToken = new JwtSecurityToken(
            _jwtOptions.Issuer,
            _jwtOptions.Audience,
            claims,
            DateTime.Now,
            DateTime.Now.AddSeconds(_jwtOptions.ExpiresIn),
            signingCredentials
        );

        // 5. 将token变为string
        var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
        var result = new JwtResponse
        {
            access_token = token,
            expires_in = _jwtOptions.ExpiresIn
        };
        return result;
    }

    /// <summary>
    /// 测试token是否在有效期
    /// </summary>
    /// <returns></returns>
    public virtual bool Test(string accessToken)
    {
        var tokenHandler = new JwtSecurityTokenHandler();

        try
        {
            tokenHandler.ValidateToken(accessToken, new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SecretKey)),
                ValidateIssuer = true,
                ValidIssuer = _jwtOptions.Issuer,
                ValidateAudience = true,
                ValidAudience = _jwtOptions.Audience,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero // 严格验证过期时间
            }, out var _);
        }
        catch
        {
            return false;
        }
        return true;
    }
}
